<?php
namespace ShenerCloud\Data;

use ShenerCloud\Data\Model\Parameter;
use ShenerCloud\Data\Model\Token;
use ShenerCloud\Exception\DataException;
use ShenerCloud\Data\Http\Request;
use ShenerCloud\Data\Exception\RequestException;
use ShenerCloud\Data\Http\Response;
use ShenerCloud\Data\Model\Source;

/***
 * 授权模式分为二种
 * 1、平台应用授权,平台应用授权服务端会检测授权IP地址,只允许添加为白名单的IP才可以正常获取授权
 * 2、基础用户授权,此授权必须要使用相应的SN号进行鉴权,同时要传入应用APPID,只有授权的SN号才获得授权
 * @author shene
 *
 */
class DataClient
{
    private $parameter;
    private $token;
    
    private $timeout=120;
    private $connectTimeout=120;
    private $redirects=0;
    private $maxRetries=5;
    private $debug=false;
    
    const USER_TOKEN_URL = '/oauth/user/token';
    const USER_REFRESH_TOKEN_URL = '/oauth/user/refresh';
    const AUTH_SOURCE_GET_URL = '/oauth/source/get';
    const AUTH_SOURCE_INFO_URL = '/oauth/source/info';
    const AUTH_SOURCE_ADDR_URL = '/oauth/source/addr';
    
    public function __construct(Parameter $parameter){
        $this->parameter = $parameter;
        $this->token = new Token($this->parameter);
        $this->source = new Source();
    }
    
    private function sign(int $time,$token="")
    {
        $time = intval($time);
        $token = trim(stripslashes($token));
        if ($time <= 0)
            return '';
        $med = $this->parameter->appsecret;
        if (!empty($token))
            $med = $token;
        return md5(md5($this->parameter->openid.$med.$time));
    }
    
    /***
     * 授权获取Token,平台授权不用传SN,用户授权必须传SN
     * @param string $sn
     * @throws DataException
     * @return string
     */
    private function getAccessToken()
    {
        if (!empty($this->parameter->sn)){
            $sn = trim(stripslashes($sn));
        }
        //检查参数是否完整
        if (empty($this->parameter->openid)
            || empty($this->parameter->appsecret))
            throw new DataException("Openid are't config");
            
        if ($this->token->checkExpire())
        {
            if ($this->token->checkRefreshToken())
            {//需要刷新Token
                $params['request_url'] = $this->parameter->host.self::USER_REFRESH_TOKEN_URL;
                $time = time();
                $params['argement'] = [
                    'Refresh_token'=>$this->parameter->refresh_token,
                    'Sign'=>$this->sign($time,$this->parameter->token),
                    'Time'=>date('Y-m-d H:i:s',$time)
                ];
                $this->token = $this->token->parseRequest($this->request($params));
            }
            return $this->token->access_token;
        }
        
        $params['request_url'] = $this->parameter->host.self::USER_TOKEN_URL;
        $time = time();
        $params['argement'] = [
            'Openid'=>$this->parameter->openid,
            'Sign'=>$this->sign($time),
            'Time'=>date('Y-m-d H:i:s',$time)
        ];
        $this->token = $this->token->parseRequest($this->request($params));
        return $this->token->access_token;
    }
    
    /***
     * 获取资源集合
     * @param string $media
     * @param int $page
     * @param int $count
     * @param array $condition
     * @return boolean|array
     */
    public function getSourceList(string $media='',int $page=0,int $count=10,array $condition=[])
    {
        if (!empty($media))
            $media = trim(stripslashes($media));
        $page = intval($page);
        $count = intval($count);
        if ($count > 100 || $count <= 0)
            throw new DataException("request source count must >0 and <100");
        $params['request_url'] = $this->parameter->host.AUTH_SOURCE_GET_URL;
        $params['argement'] = [
            'Media'=>$media_id,
            'Token'=>$this->getAccessToken(),
            'Page'=>$page+1,
            'Offset'=>$count,
            'Condition'=>$condition
        ];
        $this->source = $this->source->parseRequest($this->request($params));
        return $this->source->getList();
    }
    
    /***
     * 获取资源详细信息
     * @param string $media
     * @return boolean|\ShenerCloud\Data\Model\Source|boolean
     */
    public function getSourceInfo(string $media)
    {
        if (empty($media))
            return false;
        $media = trim(stripcslashes($media));
        $params['request_url'] = $this->parameter->host.self::AUTH_SOURCE_INFO_URL;
        $params['argement'] = [
            'Media'=>$media,
            'Token'=>$this->getAccessToken()
        ];
        $this->source = $this->source->parseRequest($this->request($params));
        return $this->source->getOne();
    }
    
    /***
     * 获取资源实际访问地址
     * @param string $media
     * @return boolean|\ShenerCloud\Data\Model\Source|boolean
     */
    public function getSourceAddr(string $media)
    {
        if (empty($media))
            return false;
        $media = trim(stripslashes($media));
        $params['request_url'] = $this->parameter->host.self::AUTH_SOURCE_ADDR_URL;
        $params['argement'] = [
            'Media'=>$media,
            'Token'=>$this->getAccessToken()
        ];
        $this->source = $this->source->parseRequest($this->request($params));
        return $this->source->getOne();
    }
    
    /***
     * 设置Debug是否开启,True|False
     * @param bool $flag
     */
    public function setDebug(bool $flag)
    {
        $flag = boolval($flag);
        $this->debug = $flag;
    }
    
    /***
     * Request请求
     * @param array $params
     * @param boolean $debug
     * @throws DataException
     * @return boolean|array
     */
    protected function request(array $params)
    {
        $request_url = isset($params['request_url'])?trim($params['request_url']):'';
        $argement = isset($params['argement'])?$params['argement']:array();
        
        if (empty($request_url)){
            throw new DataException("request url is empty");
        }
        
        //创建请求
        $request = new Request($request_url);
        if ($this->timeout !== 0) {
            $request->timeout = $this->timeout;
        }
        if ($this->connectTimeout !== 0) {
            $request->connect_timeout = $this->connectTimeout;
        }
        $request->ssl_verification = false;
        $request->debug_mode = $this->debug;
        $request->set_method('post');
        $request->set_body($argement);
        
        try {
            $request->send_request();
        } catch (RequestException $e) {
            throw(new DataException('RequestCoreException: ' . $e->getMessage()));
        }
        $response_header = $request->get_response_header();
        $data = new Response($response_header, $request->get_response_body(), $request->get_response_code());
        
        //如果返回错误那就休眠重新请求几次
        if ((integer)$request->get_response_code() === 500) {
            echo $data->body;
            return false;
        }
        
        $this->redirects = 0;
        return json_decode($data->body);
    }
}